package com.wish.nettywebsocket;

import com.wish.common.MyUtils;
import com.wish.nettywithpack.NettyRobotServerWithPack;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.stream.ChunkedWriteHandler;


/**
 * Netty Websocket实现通信协议栈 WebSocket VS Http
 * 1、Http为请求响应模式，半双工，虽可以在两个方向传播信息，但是不能同时传播
 * 2、Websocket为全双工，可以双向同时传播信息，它建立在TCP之上，同http一样通过TCP来传输数据
 * 3、Http消息冗长，包括消息头，消息体换行符等，一般采用文本方式传输
 * 4、Websocket互相沟通的Header是很小的-大概只有2字节。可采用二进制、文本传输
 * 5、服务器的推送，WebSocket服务器和Browser/UA都能主动的向对方发送或接收数据，就像Socket一样，
 * 不同的是WebSocket是一种建立在Web基础上的一种简单模拟Socket的协议，不再像Http一样，客户端轮询
 *
 * @author tantexian
 * @since 2016/7/15
 */
public class WebSocketServer {

    public static void main(String[] args) {
        final int port = args.length >= 1 ? Integer.parseInt(args[0]) : MyUtils.getDefaultPort();

        try {
            new WebSocketServer().bind(port);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public void bind(int port) throws InterruptedException {
        // 创建NIO线程组（Reactor封装），用于处理网络事件
        // 处理客户端连接NIO线程组
        NioEventLoopGroup accetpNioEventLoopGroup = new NioEventLoopGroup();
        // 处理网络IO事件NIO线程组
        NioEventLoopGroup handleNioEventLoopGroup = new NioEventLoopGroup();

        // ws请求地址
        final String socketUrl = "ws://" + MyUtils.getDefaultServerAddr() + ":" + MyUtils.getDefaultPort()  + "/websocket";
        ;

        try {
            // NIO服务启动辅助类
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(accetpNioEventLoopGroup, handleNioEventLoopGroup)// 将线程组传递到group中
                    .channel(NioServerSocketChannel.class)// 类似java
                    // nio中ServerSocketChannel
                    .option(ChannelOption.SO_BACKLOG, 1024)// 设置TCP参数
                    .childHandler(new ChannelInitializer<SocketChannel>() {

                        protected void initChannel(SocketChannel socketChannel)
                                throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast("HttpServerCodec", new HttpServerCodec());
                            pipeline.addLast("HttpObjectAggregator", new HttpObjectAggregator(1024));
                            pipeline.addLast("ChunkedWriteHandler", new ChunkedWriteHandler());
                            pipeline.addLast(new WebSocketServerHandler(socketUrl));
                        }
                    });// 绑定IO事件处理类，类似java nio中的handler，主要用来处理网络IO事件

            // 绑定端口，然后调用同步阻塞方法
            ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
            System.out.println(
                    "I,m a smart netty websocket robot and wait for you ask. [I'm listen on port " + port + "]\n websocket url is :" + socketUrl);
            // 等待链路关闭之后，才退出main函数
            channelFuture.channel().closeFuture().sync();
        } finally {
            // 优雅关闭退出
            accetpNioEventLoopGroup.shutdownGracefully();
            handleNioEventLoopGroup.shutdownGracefully();
        }

    }
}
